//---------------------------------------------------------------------------

#include "vcl_stl.h"
#pragma hdrstop

#include "h_base.h"
#include "h_xml.h"
#include "h_global.h"
using namespace h_base;
using namespace h_xml;

#include "h_g.h"
#include "h_server.h"

#include "h_portal.h"

#include "h_i18n.h"
#include "t_mainform.h"
#include "t_batchform.h"
//---------------------------------------------------------------------------

void __fastcall HOutlineThread::Execute()
{
   UTF8String IpAddr;
   int Port;

   h_g::WriteLog("ProcessID = %d, ThreadID = %x, Batch = %p, Idx = %3d",
      GetCurrentProcessId(), ThreadID, FBatch, FBatch->Idx);
   randomize();
   
   for ( ; ; )
   {
      if ( h_g::ExitFlag )
      {
         break;
      }
      if ( !FBatch->AbortFlag && !FBatch->PaintingFlag )
      {
         h_g::Outline(FBatch);
      }
      if ( h_g::ExitFlag )
      {
         break;
      }
      FBatch->AbortFlag = false;
      FRefreshEvent->ResetEvent();
      FRefreshEvent->WaitFor(h_g::Interval * 1000);
   }
}

__fastcall HBatchIcon::HBatchIcon(Classes::TComponent* AOwner, int AIdx)
   : TGraphicControl(AOwner), FIdx(AIdx), FEntered(false), FAbortFlag(false),
     FPaintingFlag(false)
{
   Cs = new TCriticalSection();
   FThread = new HOutlineThread(true, this);
   FRefreshXml = new HXmlTree;
   ShowHint = true;
   FDecompressBuf = (char*)malloc((1024 * 1024L + 1024 * 4) * 2);
}

__fastcall HBatchIcon::~HBatchIcon()
{
   delete FRefreshXml;
   delete FThread;
   FThread = NULL;
   delete Cs;
   Cs = NULL;
   free(FDecompressBuf);
}

void __fastcall HBatchIcon::Paint(void)
{
   h_g::HIconType Status = OutlineStatus.Status;

   if ( Status != h_g::itPaused && Status != h_g::itUnknown &&
        OutlineStatus.AlarmType != "" )
   {
      Status = h_g::itAlarm;
   }

   if ( h_g::HomepageLargeIcon )
   {
      Canvas->Draw(0, 0, h_g::BitmapServer[h_g::itNormal]);
      Canvas->Draw(0, h_g::BitmapServer[h_g::itNormal]->Height,
         h_g::BitmapServerBg2[Status]);
   }
   else
   {
      Canvas->Draw(0, 0, h_g::BitmapServerBg[Status]);
   }

   TRect Rect(ClientRect);

   if ( h_g::HomepageLargeIcon )
   {
      Rect.Top += h_g::BitmapServer[h_g::itNormal]->Height;
   }

   int i, j;
   int x, y;
   UTF8String Text = Outline.Caption;

   Rect.Left += 6;
   Rect.Right -= 1 + 6;
   Rect.Bottom -= 3;
   Canvas->Font->Name = "Arial";
   i = Canvas->TextWidth(Text);
   j = Rect.Right - Rect.Left;

   if( i < j )
      x = Rect.Left + ( j - i ) / 2;
   else
      x = Rect.Left;

   i = Canvas->TextHeight(Text);
   j = Rect.Bottom - Rect.Top;

   if( i < j )
      y = Rect.Top + ( j - i ) / 2;
   else
      y = Rect.Top;

   Canvas->Brush->Style = bsClear;
   Canvas->Font->Color = h_g::IconTextColors[Status];
   Canvas->TextRect(Rect, x, y, Text);
}

static UTF8String __fastcall FormatTime(const UTF8String &Str)
{
   if ( Str.Length() < 14 )
   {
      return Str;
   }

   char Result[80 + 1];
   char *Des = Result;
   const char *Src = Str.c_str();

   memcpy(Des, Src, 4);
   Src += 4;
   Des += 4;
   *Des++ = '/';
   memcpy(Des, Src, 2);
   Src += 2;
   Des += 2;
   *Des++ = '/';
   memcpy(Des, Src, 2);
   Src += 2;
   Des += 2;
   *Des++ = ' ';
   *Des++ = ' ';
   memcpy(Des, Src, 2);
   Src += 2;
   Des += 2;
   *Des++ = ':';
   memcpy(Des, Src, 2);
   Src += 2;
   Des += 2;
   *Des++ = ':';
   memcpy(Des, Src, 2);
   Src += 2;
   Des += 2;
   *Des = '\0';
   return UTF8String(Result);
}

void __fastcall HBatchIcon::SetOutlineStatus(const HOutlineStatus &OutlineStatus)
{
   FOutlineStatus = OutlineStatus;

   char TmpStr[8192 + 1];

   snprintf(TmpStr, 8192, h_g::I18nString("h_portal:OUTLINE_HINT"),
      FormatTime(OutlineStatus.StartTime).c_str(),
      FormatTime(OutlineStatus.EndTime).c_str(),
      OutlineStatus.CompletedRatio.c_str(),
      OutlineStatus.Banner.c_str(),
      Outline.Description.c_str());
   Hint = UTF8String(TmpStr);
   Invalidate();
}

void __fastcall HBatchIcon::SetEntered(bool AEntered)
{
   FEntered = AEntered;

   if ( FEntered )
   {
      Lock();
      LastStartTime = "UNKNOWN";
      LastRefreshTick = "";
      Unlock();
      Refresh();
   }
}

__fastcall HPortal::HPortal(
   Classes::TComponent* AOwner) : TScrollingWinControl(AOwner)
{
   Canvas = new TControlCanvas;
   Canvas->Control = this;
   DoubleBuffered = true;
   FColQty = 1;
   CurrentBatch = NULL;
   AutoScroll = true;
}

__fastcall HPortal::~HPortal()
{
   delete Canvas;
}

void __fastcall HPortal::GetAlarmTime(const char *TimeStr, int &Hour, int &Min)
{
   int Pos = 0;
   char w[80 + 1];

   Pos += ReadWord(TimeStr + Pos, w, " :", 80);
   Hour = StrToInt(w);

   if ( Hour < 0 || Hour > 23 )
   {
      Hour = -1;
      Min = -1;
      return;
   }

   Pos += ReadWord(TimeStr + Pos, w, " :", 80);

   if ( strcmp(w, ":") != 0 )
   {
      Hour = -1;
      Min = -1;
      return;
   }

   Pos += ReadWord(TimeStr + Pos, w, " :", 80);
   Min = StrToInt(w);

   if ( Min < 0 || Hour > 59 )
   {
      Hour = -1;
      Min = -1;
      return;
   }
}

void __fastcall HPortal::Init(int ColQty, HXmlTree *Cfg,
   const UTF8String &GotoIp, int GotoPort, const UTF8String &GotoGroup)
{
   int IconWidth;
   int IconHeight;

   if ( h_g::HomepageLargeIcon )
   {
      IconWidth = h_g::BitmapServerBg2[h_g::itNormal]->Width;
      IconHeight = h_g::BitmapServer[h_g::itNormal]->Height +
         h_g::BitmapServerBg2[h_g::itNormal]->Height;
   }
   else
   {
      IconWidth = h_g::BitmapServerBg[h_g::itNormal]->Width;
      IconHeight = h_g::BitmapServerBg[h_g::itNormal]->Height;
   }

   FColQty = ColQty;
   vector<HXmlTree*> Nodes;
   HBatchIcon *GotoBatch = NULL;

   Cfg->GetChildren("SERVER", Nodes);


   for ( int i = 0; i < Nodes.size() && i < h_g::LicQty; i++ )
   {
      HXmlTree *Node = Nodes[i];
      HBatchIcon *Icon = new HBatchIcon(this, i);
      HBatchOutline Outline;
      Outline.Name = Node->GetValue("NAME").c_str();
      Outline.Caption = Node->GetValue("CAPTION").c_str();
      Outline.IpAddr = Node->GetValue("IP_ADDR").c_str();
      Outline.Port = StrToInt(Node->GetValue("PORT").c_str());
      Outline.HotbackIpAddr = Node->GetValue("HOTBACK_IP_ADDR").c_str();
      Outline.HotbackPort = StrToInt(Node->GetValue("HOTBACK_PORT").c_str());
      Outline.Protocol = Node->GetValue("PROTOCOL").c_str();
      Outline.EnableRestart = Node->GetValueUpper("ENABLE_RESTART") == "TRUE";
      Outline.ShowBatchDate = Node->GetValueUpper("SHOW_BATCH_DATE", "TRUE") == "TRUE";
      Outline.Offline = Node->GetValueUpper("OFFLINE") == "TRUE";
      Outline.StartWindow = Node->GetValue("START_WINDOW").c_str();
      Outline.FadingPeriod = Node->GetValue("FADING_PERIOD").c_str();
      if ( Outline.FadingPeriod == "" )
      {
         Outline.FadingPeriod = h_g::FadingPeriod;
      }
      Outline.BatchInterval = Node->GetValue("BATCH_INTERVAL").c_str();
      Outline.JobNameDelimiter = Node->GetValue("JOB_NAME_DELIMITER", ":").c_str();
      if ( Outline.Protocol == "" )
      {
         Outline.Protocol = "0208";
      }
      Outline.Description = Node->GetValues("DESCRIPTION").c_str();
      if ( GotoBatch == NULL && Outline.IpAddr == GotoIp &&
           Outline.Port == GotoPort )
      {
         GotoBatch = Icon;
         HNavInfo NavInfo;
         NavInfo.ServerIdx = Icon->Idx;
         NavInfo.GroupName = GotoGroup;
         Icon->NavInfo = NavInfo;
         PostMessage(MainForm->Handle, HM_ENTERBATCH, (long)GotoBatch, 0);
      }
      if ( Outline.Offline )
      {
         HOutlineStatus OutlineStatus;
         OutlineStatus.Status = h_g::itNormal;
         OutlineStatus.StatusStr = "OFFLINE";
         Icon->OutlineStatus = OutlineStatus;
      }
      Icon->Outline = Outline;
      Icon->Parent = this;
      Icon->Width = IconWidth;
      Icon->Height = IconHeight;
      Icon->Left = ( i % FColQty ) * ( IconWidth + 16 ) + 8;
      Icon->Top = ( i / FColQty ) * ( IconHeight + 16 ) + 8;
      Icon->StartThread();
      Icon->Hint = Outline.Description;
      IconVec.push_back(Icon);
      IconMap[Icon->Outline.Caption] = Icon;
   }

   Sleep(500);
}

void __fastcall HPortal::RefreshCaption()
{
   int IconWidth;
   int IconHeight;

   if ( h_g::HomepageLargeIcon )
   {
      IconWidth = h_g::BitmapServerBg2[h_g::itNormal]->Width;
      IconHeight = h_g::BitmapServer[h_g::itNormal]->Height +
         h_g::BitmapServerBg2[h_g::itNormal]->Height;
   }
   else
   {
      IconWidth = h_g::BitmapServerBg[h_g::itNormal]->Width;
      IconHeight = h_g::BitmapServerBg[h_g::itNormal]->Height;
   }

   for ( int i = 0; i < IconVec.size(); i++ )
   {
      HBatchIcon *Icon = IconVec[i];
      Icon->Width = IconWidth;
      Icon->Height = IconHeight;
      Icon->Left = ( i % FColQty ) * ( IconWidth + 16 ) + 8;
      Icon->Top = ( i / FColQty ) * ( IconHeight + 16 ) + 8;
   }

   Invalidate();
}

void __fastcall HPortal::Refresh()
{
   for ( int i = 0; i < IconVec.size(); i++ )
   {
      IconVec[i]->Refresh();
   }
}

void __fastcall HPortal::Close()
{
   Refresh();
/*
   for ( int i = 0; i < IconVec.size(); i++ )
   {
      IconVec[i]->WaitThread();
   }
   */
}

void __fastcall HPortal::SetCurrentBatch(HBatchIcon *Batch)
{
   InvalidateCurrentBatchRect();
   CurrentBatch = Batch;
   InvalidateCurrentBatchRect();
}

void __fastcall HPortal::SetCurrentBatch(int Idx)
{
   SetCurrentBatch(IconVec[Idx]);
}

void __fastcall HPortal::WndProc(TMessage &Message)
{
   if( Message.Msg >= WM_MOUSEFIRST &&
       Message.Msg <= WM_MOUSELAST &&
       Message.Msg != WM_MOUSEWHEEL )
   {
      TControl::WndProc(Message);
      return;
   }

   if ( Message.Msg == WM_MOUSEWHEEL )
   {
      int i = (signed short)(Message.WParam >> 16);
      int OldPos = VertScrollBar->Position;
      VertScrollBar->Position -= i;
      if ( VertScrollBar->Position != OldPos )
      {
         Invalidate();
      }
   }

   if ( Message.Msg == WM_HSCROLL ||
        Message.Msg == WM_VSCROLL )
   {
      Invalidate();
   }
   inherited::WndProc(Message);
}

void __fastcall HPortal::WMPaint(TWMPaint &Message)
{
   HDC DC;
   TPaintStruct PS;

   static bool First = true;

   if ( First )
   {
      MainForm->InitWidth = Canvas->ClipRect.Width() + 16;
      MainForm->InitHeight = Canvas->ClipRect.Height() +
         MainForm->PanelAttention->Height + 32;
      First = false;
   }


   int BgWidth = MainForm->InitWidth - ( MainForm->Width - Width );
   int BgHeight = MainForm->InitHeight - ( MainForm->Height - Height );

   if( Message.DC == 0)
      DC = BeginPaint(Handle, &PS);
   else
      DC = Message.DC;

   Canvas->Lock();
   Canvas->Handle = DC;

   Canvas->Brush->Color = h_g::Homepage->Canvas->Pixels[0][0];
   Canvas->FillRect(Canvas->ClipRect);
   Canvas->Draw(BgWidth - h_g::Homepage->Width
//      - HorzScrollBar->Position
      ,
      BgHeight - h_g::Homepage->Height
//      - VertScrollBar->Position
      ,
      h_g::Homepage);

   if ( h_g::CustLogoFlag && h_g::CustLogo != NULL )
   {
      Canvas->Draw(BgWidth - h_g::CustLogo->Width
//         - HorzScrollBar->Position
         ,
         BgHeight - h_g::CustLogo->Height
//         - VertScrollBar->Position
         ,
         h_g::CustLogo);
   }

   if ( CurrentBatch != NULL )
   {
      Canvas->Brush->Color = clBlack;
      Canvas->FrameRect(TRect(CurrentBatch->Left - 1, CurrentBatch->Top - 1,
         CurrentBatch->Left + CurrentBatch->Width + 1,
         CurrentBatch->Top + CurrentBatch->Height + 1));
   }

   PaintControls(DC, NULL);
   
   if( Message.DC == 0 )
      EndPaint(Handle, &PS);
}

void __fastcall HPortal::WMLButtonDown(TWMLButtonDown &Message)
{
   SetCurrentBatch(GetBatchByPos(Message.XPos, Message.YPos));
}

void __fastcall HPortal::WMLButtonDblClk(TWMLButtonDblClk &Message)
{
   SetCurrentBatch(GetBatchByPos(Message.XPos, Message.YPos));
   ShowBatchProperties();
}

void __fastcall HPortal::WMRButtonUp(TWMRButtonUp &Message)
{
   SetCurrentBatch(GetBatchByPos(Message.XPos, Message.YPos));
   inherited::Dispatch(&Message);
}

HBatchIcon * __fastcall HPortal::GetBatchByPos(int XPos, int YPos)
{
   for ( int i = 0; i < IconVec.size(); i++ )
   {
      HBatchIcon *Icon = IconVec[i];
      if ( PosInRect(XPos, YPos, TRect(Icon->Left, Icon->Top,
             Icon->Left + Icon->Width, Icon->Top + Icon->Height)) )
      {
         return Icon;
      }
   }

   return NULL;
}

void __fastcall HPortal::InvalidateCurrentBatchRect()
{
   if ( CurrentBatch == NULL )
   {
      return;
   }

   RECT Rect;
   Rect.left = CurrentBatch->Left - 1;
   Rect.top = CurrentBatch->Top - 1;
   Rect.right = CurrentBatch->Left + CurrentBatch->Width + 1;
   Rect.bottom = CurrentBatch->Top + CurrentBatch->Height + 1;
   InvalidateRect(Handle, &Rect, true);
}

void __fastcall HPortal::ShowBatchProperties()
{
   if ( CurrentBatch == NULL )
   {
      return;
   }

   HServer::LockRefresh();
   BatchForm->ShowProperties();
   HServer::UnlockRefresh();
}

HBatchIcon * __fastcall HPortal::GetFirstBatch()
{
   if ( IconVec.empty() )
   {
      return NULL;
   }
   else
   {
      return IconVec[0];
   }
}

void __fastcall HPortal::SaveToBatList(map<int, HBatListInfo> &BatMap)
{
   for ( int i = 0; i < IconVec.size(); i++ )
   {
      HBatchIcon *Icon = IconVec[i];
      HBatListInfo Info;
      Info.Idx = i;
      Icon->Lock();
      HBatchOutline Outline = Icon->Outline;
      HOutlineStatus OutlineStatus = Icon->OutlineStatus;
      Icon->Unlock();
      Info.Name = Outline.Caption;
      {
         char TmpStr[500 + 1];
         const char *s = Outline.Description.c_str();
         int j = 0;
         for ( ; j < 500 && *s != '\0'; j++, s++ )
         {
            if ( *s == '\n' )
            {
               TmpStr[j] = ' ';
            }
            else
            {
               TmpStr[j] = *s;
            }
         }
         TmpStr[j] = '\0';
         Info.Description = TmpStr;
      }
      switch ( OutlineStatus.Status )
      {
      case h_g::itWaiting :
         Info.Status = "WAITING";
         break;
      case h_g::itRunning :
         Info.Status = "RUNNING";
         break;
      case h_g::itSuccess :
         Info.Status = "SUCCESS";
         break;
      case h_g::itFailed :
         Info.Status = "FAILED";
         break;
      case h_g::itPaused :
         Info.Status = "PAUSED";
         break;
      default :
         Info.Status = "UNKNOWN";
         break;
      }
      Info.StartTime = OutlineStatus.StartTime;
      Info.EndTime = OutlineStatus.EndTime;
      if ( Info.StartTime == "" || Info.EndTime == "" )
      {
         Info.ElapsedTime = "";
      }
      else
      {
         Info.ElapsedTime = DiffTime(Info.StartTime, Info.EndTime);
      }
      Info.BatchDate = OutlineStatus.BatchDate;
      Info.NextScheduleDate = OutlineStatus.NextScheduleDate;
      BatMap[Info.Idx] = Info;
   }
}

HBatchIcon * __fastcall HPortal::FindByCaption(const UTF8String &Caption)
{
   map<UTF8String, HBatchIcon*>::iterator Iter = IconMap.find(Caption);

   if ( Iter == IconMap.end() )
   {
      return NULL;
   }
   else
   {
      return Iter->second;
   }
}

__fastcall HLogoIcon::HLogoIcon(System::Classes::TComponent* AOwner)
   : TGraphicControl(AOwner)
{
}

__fastcall HLogoIcon::~HLogoIcon()
{
}

void __fastcall HLogoIcon::Paint()
{
   h_g::DrawLogo(Canvas);
}

#pragma package(smart_init)
